package thesis.filesharing.web.controller;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import thesis.filesharing.bo.GroupBO;
import thesis.filesharing.bo.SemesterBO;
import thesis.filesharing.bo.StudentBO;
import thesis.filesharing.model.Clazz;
import thesis.filesharing.model.Group;
import thesis.filesharing.model.Student;
import thesis.filesharing.web.auth.AuthUtil;
import thesis.filesharing.web.util.PropertiesUtil;
import thesis.filesharing.web.validator.RegisterGroupValidator;
import thesis.filesharing.web.validator.UpdateRegisterGroupValidator;
import thesis.filesharing.web.viewmodel.GroupViewModel;
import thesis.filesharing.web.viewmodel.RegisterGroupViewModel;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

@Controller
public class GroupController {
	
	@Autowired
	private GroupBO groupBO;
	
	@Autowired
	private StudentBO studentBO;
	
	@Autowired
	private SemesterBO semesterBO;
	
	@Autowired
	private RegisterGroupValidator registerGroupValidator;
	
	@Autowired
	private UpdateRegisterGroupValidator updateRegisterGroupValidator;
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/registerGroup", method = RequestMethod.GET)
	public String getRegisterGroupForm(@RequestParam(value = "key", required = false) String classKey, ModelMap model) {
		model.addAttribute("classes", getClassesStudentRegistered());
		
		if (classKey != null && !"NONE".equals(classKey)) {
			model.addAttribute("groups", getListGroupViewModel(classKey));
			
			String studentId = AuthUtil.getCurrentAuthenticatedUsername();
			Student s = studentBO.findStudentById(studentId);
			Group g = groupBO.findGroupStudentRegisteredInClass(s.getStudentKey(), classKey);
			RegisterGroupViewModel registerGroupViewModel = null;
			if (g != null) {
				Set<Key> groupMemberKeys = g.getGroupMembers();
				StringBuilder builder = new StringBuilder();
				String leaderId = g.getGroupLeader().getStudentId();
				for (Key k : groupMemberKeys) {
					Student student = studentBO.findStudentByKey(k);
					if (student != null) {
						if (leaderId.equals(student.getStudentId())) {
							builder.insert(0, leaderId + ", ");
						} else {
							builder.append(student.getStudentId()).append(", ");
						}
					}
				}
				String studentIds = "";
				if (builder.length() > 0) {
					studentIds = builder.substring(0, builder.length() - 2);
				}
				registerGroupViewModel = new RegisterGroupViewModel(classKey, g.getGroupName(), g.getTopicName(), studentIds);
				model.addAttribute("registerGroupViewModel", registerGroupViewModel);
				return "student/updateRegisterGroup";
			} else {
				registerGroupViewModel = new RegisterGroupViewModel();
				registerGroupViewModel.setClassKey(classKey);
				model.addAttribute("registerGroupViewModel", registerGroupViewModel);
				return "student/registerGroup";
			}
		}
		
		return "student/getRegisterClasses";
	}
	
	private List<Clazz> getClassesStudentRegistered() {
		String studentId = AuthUtil.getCurrentAuthenticatedUsername();
		Integer semester = semesterBO.getCurrentSemester().getSemesterName();
		List<Clazz> classes = studentBO.listClassesStudentRegistered(studentId, semester);
		return classes;
	}
	
	private List<GroupViewModel> getListGroupViewModel(String classKey) {
		List<Group> groups = groupBO.listGroupsByClass(KeyFactory.stringToKey(classKey));
		if (groups != null) {
			List<GroupViewModel> groupViewModels = new ArrayList<GroupViewModel>();
			List<Student> students = null;
			Student s = null;
			for (Group group : groups) {
				Set<Key> memberKeys = group.getGroupMembers();
				students = new ArrayList<Student>();
				for (Key k : memberKeys) {
					s = studentBO.findStudentByKey(k);
					if (s != null) {
						students.add(s);
					}
				}
				groupViewModels.add(new GroupViewModel(KeyFactory.keyToString(group.getGroupKey()), group.getGroupName(), group.getTopicName(), students));
			}
			return groupViewModels;
		}
		return null;
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/registerGroup", method = RequestMethod.POST)
	public ModelAndView processRegisterGroup(
			@ModelAttribute("registerGroupViewModel") RegisterGroupViewModel registerGroupViewModel, 
			BindingResult bindingResult, SessionStatus status, ModelMap model, HttpSession session, HttpServletRequest request) {
		registerGroupValidator.validate(registerGroupViewModel, bindingResult);
		if (bindingResult.hasErrors()) {
			model.addAttribute("classes", getClassesStudentRegistered());
			return new ModelAndView("student/registerGroup");
		} else {
			status.setComplete();
			
			Group group = new Group();
			group.setGroupName(registerGroupViewModel.getGroupName());
			group.setTopicName(registerGroupViewModel.getTopicName());
			String studentIdStr = registerGroupViewModel.getStudentIds().trim().replace(" ", "");
			String[] studentIds = studentIdStr.split(",");
			Key classKey = KeyFactory.stringToKey(registerGroupViewModel.getClassKey());
			groupBO.saveGroup(group, studentIds, classKey);
			
			session.setAttribute("msg", PropertiesUtil.getProperty("group.create.success"));
			return new ModelAndView(new RedirectView("/student/registerGroup.html?key=" + registerGroupViewModel.getClassKey()));
		}
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/updateRegisterGroup", method = RequestMethod.POST)
	public ModelAndView processUpdateRegisterGroup(
			@ModelAttribute("registerGroupViewModel") RegisterGroupViewModel registerGroupViewModel, 
			BindingResult bindingResult, SessionStatus status, ModelMap model, HttpSession session, HttpServletRequest request) {
		
		updateRegisterGroupValidator.validate(registerGroupViewModel, bindingResult);
		
		if (bindingResult.hasErrors()) {
			model.addAttribute("classes", getClassesStudentRegistered());
			return new ModelAndView("student/updateRegisterGroup");
		} else {
			status.setComplete();
			
			String currentStudentId = AuthUtil.getCurrentAuthenticatedUsername();
			Student currentStudent = studentBO.findStudentById(currentStudentId);
			Group currentGroup = groupBO.findGroupStudentRegisteredInClass(currentStudent.getStudentKey(), registerGroupViewModel.getClassKey());
			Group group = new Group(currentGroup.getGroupKey(), registerGroupViewModel.getGroupName(), registerGroupViewModel.getTopicName());
			String studentIdStr = registerGroupViewModel.getStudentIds().trim().replace(" ", "");
			String[] studentIds = studentIdStr.split(",");
			groupBO.updateGroup(group, new ArrayList<String>(Arrays.asList(studentIds)));
			
			session.setAttribute("msg", PropertiesUtil.getProperty("group.update.success"));
			return new ModelAndView(new RedirectView("/student/registerGroup.html?key=" + registerGroupViewModel.getClassKey()));
		}
	}
	
	@PreAuthorize("hasRole('ROLE_STUDENT')")
	@RequestMapping(value = "/student/deleteGroup", method = RequestMethod.GET)
	public RedirectView deleteGroupFromClass(
			@RequestParam(value = "classKey", required = true) String classKey, HttpSession session) {
		String studentId = AuthUtil.getCurrentAuthenticatedUsername();
		Student student = studentBO.findStudentById(studentId);
		if (student != null) {
			Group g = groupBO.findGroupStudentRegisteredInClass(student.getStudentKey(), classKey);
			if (g != null) {
				groupBO.deleteGroup(g.getGroupKey());
				System.out.println(PropertiesUtil.getProperty("group.delete.success"));
				session.setAttribute("msg", PropertiesUtil.getProperty("group.delete.success"));
			}
		}
		
		return new RedirectView("/student/registerGroup.html?key=" + classKey);
	}
}
